package group.sicher.lock;


import group.sicher.lock.brain.MarsLockInterceptor;
import group.sicher.lock.component.impl.MarsFairLockInterfaceComponent;
import group.sicher.lock.component.impl.MarsMultiLockInterfaceComponent;
import group.sicher.lock.configure.MarsLockConfigure;
import group.sicher.lock.constant.*;
import group.sicher.lock.factory.MarsComponentFactory;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.*;
import org.redisson.connection.balancer.LoadBalancer;
import org.redisson.connection.balancer.RandomLoadBalancer;
import org.redisson.connection.balancer.RoundRobinLoadBalancer;
import org.redisson.connection.balancer.WeightedRoundRobinBalancer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Scope;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @description: 基于RedisSon 锁封装的配置类
 * 这个类是重点
 * 将自定义配置和RedisSon的配置相结合
 * 注入IOC容器需要的bean
 * @author: aron
 * @date: 2019-08-05 11:46
 */
@Configuration
@EnableConfigurationProperties(MarsLockConfigure.class)
@Import({MarsLockInterceptor.class})
public class MarsLockAutoConfigure {

    @Autowired
    private MarsLockConfigure marsLockConfigure;


    @Bean
    public MarsComponentFactory marsComponentFactory() {
        return new MarsComponentFactory();
    }


    @Bean
    @Scope("prototype")
    public MarsFairLockInterfaceComponent marsFairLockInterfaceComponent() {
        return new MarsFairLockInterfaceComponent();
    }

    @Bean
    @Scope("prototype")
    public MarsMultiLockInterfaceComponent marsMultiLockInterfaceComponent() {
        return new MarsMultiLockInterfaceComponent();
    }


    /**
     * 创建redisSonClient
     *
     * @return RedissonClient
     */
    @Bean(name = "marsLockClient", destroyMethod = "shutdown")
    public RedissonClient redissonClient() throws URISyntaxException {
        Config config = new Config();
        MarsServerPattern serverPattern = MarsMapStore.getServerPattern(marsLockConfigure.getPattern());

        if (serverPattern == MarsServerPattern.SINGLE) {
            SingleServerConfig singleServerConfig = config.useSingleServer();
            initSingleConfig(singleServerConfig);
        }
        if (serverPattern == MarsServerPattern.CLUSTER) {
            ClusterServersConfig clusterConfig = config.useClusterServers();
            initClusterConfig(clusterConfig);
        }

        return Redisson.create(config);
    }

    /**
     * 初始化单机模式参数
     *
     * @param singleServerConfig 单机模式配置
     */
    private void initSingleConfig(SingleServerConfig singleServerConfig) throws URISyntaxException {
        MarsLockConfigure.SingleConfig singleConfig = marsLockConfigure.getSingleServer();
        singleServerConfig.setAddress(String.format("%s%s%s%s", MarsLockConstant.REDIS_URL_PREFIX, singleConfig.getAddress(), MarsLockConstant.COLON, singleConfig.getPort()));
        singleServerConfig.setClientName(marsLockConfigure.getClientName());
        singleServerConfig.setConnectionMinimumIdleSize(singleConfig.getConnMinIdleSize());
        singleServerConfig.setConnectionPoolSize(singleConfig.getConnPoolSize());
        singleServerConfig.setConnectTimeout(singleConfig.getConnTimeout());
        singleServerConfig.setDatabase(singleConfig.getDatabase());
        singleServerConfig.setDnsMonitoringInterval(singleConfig.getDnsMonitoringInterval());
        singleServerConfig.setIdleConnectionTimeout(singleConfig.getIdleConnTimeout());
        singleServerConfig.setKeepAlive(singleConfig.isKeepAlive());
        singleServerConfig.setPassword(singleConfig.getPassword());
        singleServerConfig.setRetryAttempts(singleConfig.getRetryAttempts());
        singleServerConfig.setRetryInterval(singleConfig.getRetryInterval());
        singleServerConfig.setSslEnableEndpointIdentification(marsLockConfigure.isSslEnableEndpointIdentification());
        if (marsLockConfigure.getSslKeystore() != null) {
            singleServerConfig.setSslKeystore(new URI(marsLockConfigure.getSslKeystore()));
        }
        if (marsLockConfigure.getSslKeystorePassword() != null) {
            singleServerConfig.setSslKeystorePassword(marsLockConfigure.getSslKeystorePassword());
        }
        singleServerConfig.setSslProvider(MarsLockConstant.JDK.equalsIgnoreCase(marsLockConfigure.getSslProvider()) ? SslProvider.JDK : SslProvider.OPENSSL);
    }

    /**
     * 初始化集群模式参数
     *
     * @param clusterServerConfig 集群模式配置
     */
    private void initClusterConfig(ClusterServersConfig clusterServerConfig) {
        MarsLockConfigure.ClusterConfig clusterConfig = marsLockConfigure.getClusterServer();
        String[] addressArr = clusterConfig.getNodeAddresses().split(MarsLockConstant.COMMA);
        Arrays.asList(addressArr).forEach(
                address -> clusterServerConfig.addNodeAddress(String.format("%s%s", MarsLockConstant.REDIS_URL_PREFIX, address))
        );
        clusterServerConfig.setScanInterval(clusterConfig.getScanInterval());

        ReadMode readMode = getReadMode(clusterConfig.getReadMode());
        clusterServerConfig.setReadMode(readMode);

        SubscriptionMode subscriptionMode = getSubscriptionMode(clusterConfig.getSubMode());
        clusterServerConfig.setSubscriptionMode(subscriptionMode);

        LoadBalancer loadBalancer = getLoadBalancer(clusterConfig.getLoadBalancer(), clusterConfig.getWeightMaps(), clusterConfig.getDefaultWeight());
        clusterServerConfig.setLoadBalancer(loadBalancer);

        clusterServerConfig.setSubscriptionConnectionMinimumIdleSize(clusterConfig.getSubConnMinIdleSize());
        clusterServerConfig.setSubscriptionConnectionPoolSize(clusterConfig.getSubConnPoolSize());
        clusterServerConfig.setSlaveConnectionMinimumIdleSize(clusterConfig.getSlaveConnMinIdleSize());
        clusterServerConfig.setSlaveConnectionPoolSize(clusterConfig.getSlaveConnPoolSize());
        clusterServerConfig.setMasterConnectionMinimumIdleSize(clusterConfig.getMasterConnMinIdleSize());
        clusterServerConfig.setMasterConnectionPoolSize(clusterConfig.getMasterConnPoolSize());
        clusterServerConfig.setIdleConnectionTimeout(clusterConfig.getIdleConnTimeout());
        clusterServerConfig.setConnectTimeout(clusterConfig.getConnTimeout());
        clusterServerConfig.setTimeout(clusterConfig.getTimeout());
        clusterServerConfig.setRetryAttempts(clusterConfig.getRetryAttempts());
        clusterServerConfig.setRetryInterval(clusterConfig.getRetryInterval());
        clusterServerConfig.setPassword(clusterConfig.getPassword());
        clusterServerConfig.setSubscriptionsPerConnection(clusterConfig.getSubPerConn());
        clusterServerConfig.setClientName(marsLockConfigure.getClientName());
    }


    /**
     * 根据readModeType返回ReadMode
     *
     * @param readModeType 读取操作的负载均衡模式类型
     * @return ReadMode OR NULL
     */
    private ReadMode getReadMode(String readModeType) {
        if (MarsLockSubReadModeTypeConstant.SLAVE.equals(readModeType)) {
            return ReadMode.SLAVE;
        }
        if (MarsLockSubReadModeTypeConstant.MASTER.equals(readModeType)) {
            return ReadMode.MASTER;
        }
        if (MarsLockSubReadModeTypeConstant.MASTER_SLAVE.equals(readModeType)) {
            return ReadMode.MASTER_SLAVE;
        }
        return null;
    }

    /**
     * 根据subscriptionModeType返回SubscriptionMode
     *
     * @param subscriptionModeType 订阅操作的负载均衡模式类型
     * @return SubscriptionMode OR NULL
     */
    private SubscriptionMode getSubscriptionMode(String subscriptionModeType) {
        if (MarsLockSubReadModeTypeConstant.SLAVE.equals(subscriptionModeType)) {
            return SubscriptionMode.SLAVE;
        }
        if (MarsLockSubReadModeTypeConstant.MASTER.equals(subscriptionModeType)) {
            return SubscriptionMode.MASTER;
        }
        return null;
    }


    /**
     * 根据用户的配置类型设置对应的LoadBalancer
     *
     * @param loadBalancerType   负载均衡算法类名
     * @param customerWeightMaps 权重值设置，当负载均衡算法是权重轮询调度算法时该属性有效
     * @param defaultWeight      默认权重值，当负载均衡算法是权重轮询调度算法时该属性有效
     * @return LoadBalancer OR NULL
     */
    private LoadBalancer getLoadBalancer(String loadBalancerType, String customerWeightMaps, int defaultWeight) {
        if (MarsLockLoadBancesTypeConstant.RANDOM_LOAD_BALANCER.equals(loadBalancerType)) {
            return new RandomLoadBalancer();
        }
        if (MarsLockLoadBancesTypeConstant.ROUND_ROBIN_LOAD_BALANCER.equals(loadBalancerType)) {
            return new RoundRobinLoadBalancer();
        }
        if (MarsLockLoadBancesTypeConstant.WEIGHTED_ROUND_ROBIN_BALANCER.equals(loadBalancerType)) {
            Map<String, Integer> weights = new HashMap<>(16);
            String[] weightMaps = customerWeightMaps.split(MarsLockConstant.SEMICOLON);
            Arrays.asList(weightMaps).forEach(
                    weightMap -> weights.put(MarsLockConstant.REDIS_URL_PREFIX + weightMap.split(MarsLockConstant.COMMA)[0], Integer.parseInt(weightMap.split(MarsLockConstant.COMMA)[1]))
            );
            return new WeightedRoundRobinBalancer(weights, defaultWeight);
        }
        return null;
    }



}
